package com.hgxd.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hgxd.entity.pojo.Slave;
import com.hgxd.entity.pojo.SlaveHistory;
import com.hgxd.entity.res.ResQOQAnalysis;
import com.hgxd.entity.res.TotalElectricalEnergy;
import com.hgxd.entity.vo.*;
import com.hgxd.entity.res.ResYOYAnalysis;
import com.hgxd.entity.res.ResYOYVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hgxd.exception.ServiceException;
import com.hgxd.mapper.SlaveHistoryMapper;
import com.hgxd.mapper.SlaveMapper;
import com.hgxd.result.ResultCodeEnum;
import com.hgxd.service.ISlaveHistoryService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 从机变量记录表 服务实现类
 * </p>
 *
 * @author fsd
 * @since 2023-10-18
 */
@Service("SlaveHistoryServiceImpl")
public class SlaveHistoryServiceImpl extends ServiceImpl<SlaveHistoryMapper, SlaveHistory> implements ISlaveHistoryService {
    @Resource
    private SlaveHistoryMapper slaveHistoryMapper;
    @Resource
    private SlaveMapper slaveMapper;

    @Override
    public List<SlaveHistoryMsgVo> getSlaveHistoryInfo(SlaveHistoryVo slaveHistoryVo) {
        switch (slaveHistoryVo.getType()) {
            case 1:
                return getDateData(slaveHistoryVo);
            case 2:
                return getMonData(slaveHistoryVo);
            case 3:
                return getYearData(slaveHistoryVo);
            default:
                break;
        }
        return null;
//        return new PageUtils(new ArrayList<>(0), 0, slaveHistoryVo.getSize(), slaveHistoryVo.getPage());
    }

    @Override
    public List<ResYOYAnalysis> getYOY(YOYVo yoyVo) {
        // 1.判断是否合法 这行本不需要，可删
        if (!(yoyVo.getType() == 1 || yoyVo.getType() == 2 || yoyVo.getType() == 3)) {
            throw new ServiceException(ResultCodeEnum.DATA_ERROR, "type非法");
        }
        LocalDateTime nowTime = yoyVo.getTime();
        // 2.查询当前年月份的能耗
        Map<Integer, Double> nowMap = getEnergConsumptionToMap(yoyVo.getName(), nowTime);
        // 3.查询前一年月份的能耗
        LocalDateTime lastTime = nowTime.plusYears(-1);
        Map<Integer, Double> lastMap = getEnergConsumptionToMap(yoyVo.getName(), lastTime);
        System.out.println("nowMap = " + nowMap);
        System.out.println("nowMap = " + nowMap.get(12));
        // 计算对应的同比和累计同比
        List<ResYOYAnalysis> resYOYAnalyses = calculateYOY(nowMap, lastMap);
        // 5.输出
        return resYOYAnalyses;
    }

    @Override
    public List<ResQOQAnalysis> getQOQ(QOQVo qoqVo) {
        // 判断有无类型和查询的时间
        if (qoqVo.getTime() == null || qoqVo.getType() == null) {
            throw new ServiceException(ResultCodeEnum.PARAMETER_IS_EMPTY, "参数为空");
        }
        List<ResQOQAnalysis> resQOQAnalyses;
        // 判断类型且封装三个时间参数
        switch (qoqVo.getType()) {
            case 1:
                // 年 2023-1-1 00:00:00
                resQOQAnalyses = getQOQByYear(qoqVo.getSlaveNames(), qoqVo.getTime());
                break;
            case 2:
                // 月 2023-7-1 00:00:00
                resQOQAnalyses = getQOQByMonth(qoqVo.getSlaveNames(), qoqVo.getTime());
                break;
            case 3:
                // 日 2023-7-6 00:00:00
                resQOQAnalyses = getQOQByDay(qoqVo.getSlaveNames(), qoqVo.getTime());
                break;
            default:
                throw new ServiceException(ResultCodeEnum.ARGUMENT_VALID_ERROR, "参数校验异常");

        }
        return calculateQOQ(resQOQAnalyses);
    }


    @Override
    public HashMap<LocalDate, Integer> getTotalElectricityHistory() {
        LocalDate now = LocalDate.now();
        HashMap<LocalDate, Integer> objectObjectHashMap = new HashMap<>();
        for (int i = 6; i >= 0; i--) {
            LocalDate yesterday = now.plusDays(-i);
            Integer total = slaveHistoryMapper.getTotalElectricityHistoryByDate(yesterday);
            objectObjectHashMap.put(yesterday, total);
        }
        return objectObjectHashMap;


    }

    @Override
    public List<TotalElectricalEnergy> getElectricalEnergy(ResTotalElectricalEnergyVo totalElectricalEnergyVo) {
        if (totalElectricalEnergyVo.getBeginTime() == null || totalElectricalEnergyVo.getEndingTime() == null) {
            throw new ServiceException(ResultCodeEnum.ARGUMENT_VALID_ERROR, "传入时间非法");
        }
        return slaveHistoryMapper.getElectricityByTimeAndName(totalElectricalEnergyVo.getSlaveNames()
                , totalElectricalEnergyVo.getBeginTime()
                , totalElectricalEnergyVo.getEndingTime());
    }

    @Override
    public Map<Integer, Double> getTotalEnergyByHour(LocalDateTime beginTime, LocalDateTime endingTime, Integer slaveId) {
        List<SlaveHistoryMsgVo> totalEnergyByHour = slaveHistoryMapper.getTotalEnergyByHour(beginTime, endingTime, slaveId);
        System.out.println("totalEnergyByHour = " + totalEnergyByHour);
        HashMap<Integer, Double> map = new HashMap<>();
        for (int i = 0; i < 24; i++) {
            final int j = i;
            double sum = totalEnergyByHour.stream().filter(s -> s.getIdate() == j)
                    .map(SlaveHistoryMsgVo::getYgdnAll)
                    .collect(Collectors.toList())
                    .stream().mapToDouble(Double::doubleValue).sum();
            map.put(i,sum);
        }
        return map;
    }

    @Override
    public SlaveHistory getNewSlaveMessageBySlaveId(Integer slaveId) {
//        long l = System.currentTimeMillis();
        LambdaQueryWrapper<SlaveHistory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SlaveHistory::getSlaveId,slaveId)
                .orderByDesc(SlaveHistory::getUpdateTime)
                .last("limit 1");
        SlaveHistory slaveHistory = slaveHistoryMapper.selectOne(queryWrapper);
//        System.out.println("查询单个"+slaveId.toString()+" 耗时= " + (System.currentTimeMillis() - l));
        return slaveHistory;

    }

    /**
     * 计算按年分析环比
     *
     * @param slaveNames
     * @param nowBeginTime
     * @return
     */
    private List<ResQOQAnalysis> getQOQByYear(List<String> slaveNames, LocalDateTime nowBeginTime) {
        // 2023-1-1 00:00:00
        LocalDateTime nowEndingTime = nowBeginTime.plusYears(1).plusSeconds(-1);
        LocalDateTime lastBeginTime = nowBeginTime.plusYears(-1);
        LocalDateTime lastEndingTime = nowBeginTime.plusSeconds(-1);

        return slaveHistoryMapper.getQOQ(slaveNames, nowBeginTime, nowEndingTime, lastBeginTime, lastEndingTime);
    }

    /**
     * 计算按月分析环比
     *
     * @param slaveNames
     * @param nowBeginTime
     * @return
     */
    private List<ResQOQAnalysis> getQOQByMonth(List<String> slaveNames, LocalDateTime nowBeginTime) {
        // 2023-7-1 00:00:00
        LocalDateTime nowEndingTime = nowBeginTime.plusMonths(1).plusSeconds(-1);
        LocalDateTime lastBeginTime = nowBeginTime.plusMonths(-1);
        LocalDateTime lastEndingTime = nowBeginTime.plusSeconds(-1);

        return slaveHistoryMapper.getQOQ(slaveNames, nowBeginTime, nowEndingTime, lastBeginTime, lastEndingTime);
    }

    /**
     * 计算按日分析环比
     *
     * @param slaveNames
     * @param nowBeginTime
     * @return
     */
    private List<ResQOQAnalysis> getQOQByDay(List<String> slaveNames, LocalDateTime nowBeginTime) {
        // 日 2023-7-6 00:00:00
        LocalDateTime nowEndingTime = nowBeginTime.plusDays(1).plusSeconds(-1);
        LocalDateTime lastBeginTime = nowBeginTime.plusDays(-1);
        LocalDateTime lastEndingTime = nowBeginTime.plusSeconds(-1);
        return slaveHistoryMapper.getQOQ(slaveNames, nowBeginTime, nowEndingTime, lastBeginTime, lastEndingTime);
    }

    /**
     * 组装计算前端需要的环比格式
     *
     * @param list
     * @return
     */
    private List<ResQOQAnalysis> calculateQOQ(List<ResQOQAnalysis> list) {
        if (list != null) {
            for (ResQOQAnalysis resQOQAnalysis : list) {
                resQOQAnalysis.setValueAdded(NumberUtil.round(resQOQAnalysis.getNowEnergyConsumption() - resQOQAnalysis.getLastEnergyConsumption(),2,RoundingMode.HALF_UP).doubleValue());
                if (resQOQAnalysis.getLastEnergyConsumption() == 0) {
                    resQOQAnalysis.setQOQ(0.0);
                } else {
                    BigDecimal bigDecimal = BigDecimal.valueOf(resQOQAnalysis.getValueAdded() / resQOQAnalysis.getLastEnergyConsumption() * 100);
                    BigDecimal roundedNumber = bigDecimal.setScale(2, RoundingMode.HALF_UP);
                    resQOQAnalysis.setQOQ(roundedNumber.doubleValue());
                }
            }
        }
        return list;
    }

    /**
     * 根据今年和去年查到的每月电能消耗，计算对应的同比和累计同比
     *
     * @param nowMap  今年电能
     * @param lastMap 去年电能
     * @return 每月实际的对象集合
     */
    private List<ResYOYAnalysis> calculateYOY(Map<Integer, Double> nowMap, Map<Integer, Double> lastMap) {
        ArrayList<ResYOYAnalysis> list = new ArrayList<>();
        // 4.计算同比 (今年同期-去年同期)/去年同期
        //   累计同比 (今年1月到同期-去年1月到同期)/去年1月到同期
        double nowTotal = 0.00;
        double lastTotal = 0.00;
        for (int i = 1; i <= 12; i++) {
            ResYOYAnalysis resYOYAnalysis = new ResYOYAnalysis();
            resYOYAnalysis.setMonth(i);
            Double now = nowMap.get(i);
            if (now == null) {
                now = 0.00;
            }
            resYOYAnalysis.setNowYearConsumption(now);
            Double last = lastMap.get(i);
            if (last == null) {
                last = 0.00;
            }
            resYOYAnalysis.setLastYearConsumption(last);
            // 计算同比
            double a = (now - last) / last * 100;
            if ((now - last) == 0 || last == 0) {
                resYOYAnalysis.setYOY(0.0);
            } else {
                BigDecimal bigDecimalYOY = BigDecimal.valueOf(a);
                BigDecimal YOY = bigDecimalYOY.setScale(2, RoundingMode.HALF_UP);
                resYOYAnalysis.setYOY(YOY.doubleValue());
            }
            // 计算累计同比
            nowTotal += now;
            lastTotal += last;
            double b = (nowTotal - lastTotal) / lastTotal * 100;
            if ((nowTotal - lastTotal) == 0 || lastTotal == 0) {
                resYOYAnalysis.setAccumulatedYOY(0.0);
            } else {
                BigDecimal bigDecimalAccumulatedYOY = BigDecimal.valueOf(b);
                BigDecimal accumulatedYOY = bigDecimalAccumulatedYOY.setScale(2, RoundingMode.HALF_UP);
                resYOYAnalysis.setAccumulatedYOY(accumulatedYOY.doubleValue());
            }
            //放到list集合中
            list.add(resYOYAnalysis);
        }
        return list;
    }


    /**
     * <p>1 查询对应年份的每月能耗结果为list</p>
     * 2 将list集合转成map对象 结构为：key=time value=energyConsumption
     *
     * @param name 从机名称
     * @param date 需要的时间 格式：yyyy-MM-dd HH:mm:ss
     * @return Map
     */
    private Map<Integer, Double> getEnergConsumptionToMap(String name, LocalDateTime date) {
        int year = date.getYear();
        List<ResYOYVo> list = slaveHistoryMapper.getYOY(name, year);
        return list.stream()
                .collect(Collectors.toMap(ResYOYVo::getMonth, ResYOYVo::getEnergyConsumption));
    }

    DecimalFormat df = new DecimalFormat("0.00");

    /**
     * 按天统计电量
     *
     * @param slaveHistoryVo
     * @return
     */
    private List<SlaveHistoryMsgVo> getDateData(SlaveHistoryVo slaveHistoryVo) {
//        Page<Object> page = PageHelper.startPage(slaveHistoryVo.getIndex(), slaveHistoryVo.getSize());
        List<SlaveHistoryMsgVo> maps = slaveHistoryMapper.queryByInfoDAY(slaveHistoryVo);
        return maps;
//        return new PageUtils(getNewMaps(maps, "h"), page.getTotal(), slaveHistoryVo.getSize(), slaveHistoryVo.getPage());
    }

    /**
     * 按月统计电量
     *
     * @param slaveHistoryVo
     * @return
     */
    private List<SlaveHistoryMsgVo> getMonData(SlaveHistoryVo slaveHistoryVo) {
        com.github.pagehelper.Page<Object> page = PageHelper.startPage(slaveHistoryVo.getIndex(), slaveHistoryVo.getSize());
        List<SlaveHistoryMsgVo> maps = slaveHistoryMapper.queryByInfoMon(slaveHistoryVo);
        return maps;
//        return new PageUtils(getNewMaps(maps, "d"), page.getTotal(), slaveHistoryVo.getSize(), slaveHistoryVo.getPage());
    }

    /**
     * 按年统计电量
     *
     * @param slaveHistoryVo
     * @return
     */
    private List<SlaveHistoryMsgVo> getYearData(SlaveHistoryVo slaveHistoryVo) {
        Page<Object> page = PageHelper.startPage(slaveHistoryVo.getIndex(), slaveHistoryVo.getSize());
        List<SlaveHistoryMsgVo> maps = slaveHistoryMapper.queryByInfoYear(slaveHistoryVo);
        return maps;
//        return new PageUtils(getNewMaps(maps, "m"), page.getTotal(), slaveHistoryVo.getSize(), slaveHistoryVo.getPage());
    }

    private List<Map> getNewMaps(List<Map> maps, String prefix) {
        //获取salveName
        Map<Object, String> salveNameMap = getSalveNameMap(maps);
        List<Map> newMaps = new ArrayList<>();
        //根据slaveId分组
        Map<Object, List<Map>> slaveIdMap = maps.stream().collect(Collectors.groupingBy(c -> c.get("slaveId")));
        for (Map.Entry<Object, List<Map>> entry : slaveIdMap.entrySet()) {
            Map newData = new LinkedHashMap();
            newData.put("slaveId", entry.getKey());
            newData.put("salveName", salveNameMap.get(entry.getKey()));
            newData.put("name", "ygdnAll");
            List<Map> subListMap = entry.getValue();
            for (Map subMap : subListMap) {
                newData.put(prefix + subMap.get("idate"), subMap.put("ygdnAll", df.format(subMap.get("ygdnAll"))));
            }
            newMaps.add(newData);
        }
        return newMaps;
    }

    private Map<Object, String> getSalveNameMap(List<Map> maps) {
        List<Object> slaveIds = maps.stream().map(c -> c.get("slaveId")).distinct().collect(Collectors.toList());
        QueryWrapper<Slave> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(CollectionUtils.isNotEmpty(slaveIds), Slave::getId, slaveIds);
        List<Slave> slaveEntities = slaveMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(slaveEntities)) {
            return slaveEntities.stream().collect(Collectors.toMap(Slave::getId, Slave::getName));
        }
        return Collections.emptyMap();
    }
}
